GtkWidget: Avoid lingering clock frame updates
authorBastien Nocera <hadess@hadess.net>
Tue, 22 Oct 2013 16:42:01 +0000 (18:42 +0200)
committerBastien Nocera <hadess@hadess.net>
Wed, 23 Oct 2013 13:22:27 +0000 (15:22 +0200)
For some widgets, like GtkTreeView, which setup a clock frame
update during realize, it was possible to call
gdk_frame_clock_begin_updating() twice, but only ever disconnecting
from it once. This happens because the realized flag is set at an
unpredictable time by the GtkWidget's realize implementation.

Keep the signal handler ID from us connecting to the "update" signal
to avoid connecting to it twice.

This fixes high wake-up count from any application using GtkTreeView,
even idle ones.

https://bugzilla.gnome.org/show_bug.cgi?id=710666

gtk/gtkwidget.c

index c4068d1acfc75838118416b2a3d1608be982e2a2..7acfd652b44938316103cf8d9dc5f74b73beb7fe 100644 (file)
@@ -510,6 +510,7 @@ struct _GtkWidgetPrivate
 
   /* Animations and other things to update on clock ticks */
   GList *tick_callbacks;
+  guint clock_tick_id;
 
   /* A hash by GType key, containing hash tables by widget name
    */
@@ -4731,12 +4732,11 @@ unref_tick_callback_info (GtkWidget           *widget,
       g_slice_free (GtkTickCallbackInfo, info);
     }
 
-  if (priv->tick_callbacks == NULL && priv->realized)
+  if (priv->tick_callbacks == NULL && priv->clock_tick_id)
     {
       GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
-      g_signal_handlers_disconnect_by_func (frame_clock,
-                                            (gpointer) gtk_widget_on_frame_clock_update,
-                                            widget);
+      g_signal_handler_disconnect (frame_clock, priv->clock_tick_id);
+      priv->clock_tick_id = 0;
       gdk_frame_clock_end_updating (frame_clock);
     }
 }
@@ -4834,12 +4834,12 @@ gtk_widget_add_tick_callback (GtkWidget       *widget,
 
   priv = widget->priv;
 
-  if (priv->tick_callbacks == NULL && priv->realized)
+  if (priv->realized && !priv->clock_tick_id)
     {
       GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (widget);
-      g_signal_connect (frame_clock, "update",
-                        G_CALLBACK (gtk_widget_on_frame_clock_update),
-                        widget);
+      priv->clock_tick_id = g_signal_connect (frame_clock, "update",
+                                              G_CALLBACK (gtk_widget_on_frame_clock_update),
+                                              widget);
       gdk_frame_clock_begin_updating (frame_clock);
     }
 
@@ -4898,11 +4898,11 @@ gtk_widget_connect_frame_clock (GtkWidget     *widget,
   if (GTK_IS_CONTAINER (widget))
     _gtk_container_maybe_start_idle_sizer (GTK_CONTAINER (widget));
 
-  if (priv->tick_callbacks != NULL)
+  if (priv->tick_callbacks != NULL && !priv->clock_tick_id)
     {
-      g_signal_connect (frame_clock, "update",
-                        G_CALLBACK (gtk_widget_on_frame_clock_update),
-                        widget);
+      priv->clock_tick_id = g_signal_connect (frame_clock, "update",
+                                              G_CALLBACK (gtk_widget_on_frame_clock_update),
+                                              widget);
       gdk_frame_clock_begin_updating (frame_clock);
     }
 
@@ -4919,11 +4919,10 @@ gtk_widget_disconnect_frame_clock (GtkWidget     *widget,
   if (GTK_IS_CONTAINER (widget))
     _gtk_container_stop_idle_sizer (GTK_CONTAINER (widget));
 
-  if (priv->tick_callbacks)
+  if (priv->clock_tick_id)
     {
-      g_signal_handlers_disconnect_by_func (frame_clock,
-                                            (gpointer) gtk_widget_on_frame_clock_update,
-                                            widget);
+      g_signal_handler_disconnect (frame_clock, priv->clock_tick_id);
+      priv->clock_tick_id = 0;
       gdk_frame_clock_end_updating (frame_clock);
     }